package n50_atomic;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicStampedReference;

import static utils.Sleeper.sleep;

/**
 * @author fu
 * @date 2022-02-13 17:01
 * 概要：
 * ----------------------------------------------------------------
 * |                                                              |
 * | AtomicStampedReference 比 AtomicReference  多了版本号         |
 * | 这样就能解决  ：如果有其他线程修改过，则 【修改失败】              |
 * |                                                             |
 * |==============================================================
 */
@Slf4j(topic = "c.T4")
public class T5_ABA问题_用版本号解决1 {


    static AtomicStampedReference<String> ref = new AtomicStampedReference<>("A",0);

    public static void main(String[] args) throws InterruptedException {
        log.debug("main start...");
        // 获取值 A
        // 这个共享变量被它线程修改过？
        String prev = ref.getReference();
        // 获取版本号
        int stamp = ref.getStamp();
        log.debug("版本号：{}" , stamp);

        /*********************** 模拟 其他线程 对共享资源 修改 beg ***********************/

        other();
        sleep(1);

        /*********************** 模拟 其他线程 对共享资源 修改 end ***********************/

        log.debug("版本号：{}" , ref.getStamp());
        // 尝试改为 C
        log.debug("change A->C {}", ref.compareAndSet(prev, "C",stamp, stamp + 1));

        log.debug(ref.getReference());
    }

    private static void other() {

        new Thread(() -> {
            int stamp = ref.getStamp();
            log.debug("change A->B {}", ref.compareAndSet(ref.getReference(), "B",stamp, stamp + 1));
        }, "t1").start();
        sleep(0.5);

        new Thread(() -> {
            int stamp = ref.getStamp();
            log.debug("change B->A {}", ref.compareAndSet(ref.getReference(), "A",stamp, stamp + 1));
        }, "t2").start();

    }
}